package com.frame.project.service.monitor.online.imp;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.Deque;
import java.util.List;
import java.util.Optional;

import javax.persistence.criteria.Predicate;

import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.session.Session;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;

import com.frame.common.constant.ShiroConstants;
import com.frame.common.utils.StringUtils;
import com.frame.framework.shiro.session.OnlineSessionDAO;
import com.frame.project.domain.monitor.online.UserOnline;
import com.frame.project.repository.monitor.online.UserOnlineRepository;
import com.frame.project.service.monitor.online.UserOnlineService;

/**
 * 
 * @className ：UserOnlineServiceImpl
 * @describe ：当前在线会话
 */
@Service
public class UserOnlineServiceImpl implements UserOnlineService {

	@Autowired
	private UserOnlineRepository userOnlineRepository;
	
	@Autowired
    private OnlineSessionDAO onlineSessionDAO;
	
	@Autowired
    private EhCacheManager ehCacheManager;
	
	/**
     * 分页
     */
	@Override
	public Page<UserOnline> findByPage(Integer pageNo, Integer pageSize, UserOnline userOnline) {
		List<Sort.Order> orders = new ArrayList<>();
		orders.add(new Sort.Order(Sort.Direction.DESC, "id"));
		Sort sort = Sort.by(orders);
		Pageable pageable = PageRequest.of(pageNo, pageSize, sort);
		
		Page<UserOnline> page = userOnlineRepository.findAll((root, query, cb) ->{
			List<Predicate> list = new ArrayList<>();
			
			if(StringUtils.isNotBlank(userOnline.getIpaddr())) {
				list.add(cb.and(cb.like(root.get("ipaddr").as(String.class), userOnline.getIpaddr())));
			}
			
			if(StringUtils.isNotBlank(userOnline.getLoginName())) {
				list.add(cb.and(cb.like(root.get("loginName").as(String.class), userOnline.getLoginName())));
			}
			
			Predicate[] p = new Predicate[list.size()];
			return cb.and(list.toArray(p));
		},pageable);
		
		return page;
	}
	
	/**
	 * 根据ID查询
	 */
	@Override
	public UserOnline findById(Long id) {
		Optional<UserOnline> userOp = userOnlineRepository.findById(id);
		if(userOp.isPresent()) {
			return userOp.get();
		}
		return null;
	}
	
	/**
	 * 根据sessionId查询
	 */
	@Override
	public UserOnline findBySessionId(String sessionId) {
		return userOnlineRepository.findBySessionId(sessionId);
	}
	 /**
     * 保存会话信息
     * 
     * @param online 会话信息
     */
    @Override
    public void saveOnline(UserOnline online)
    {
    	UserOnline uo = userOnlineRepository.findBySessionId(online.getSessionId());
    	if(uo == null) {
    		userOnlineRepository.save(online);
    	}else {
    		uo.setDeptName(online.getDeptName());
    		uo.setLoginName(online.getLoginName());
    		uo.setStartTimestamp(online.getStartTimestamp());
    		uo.setLastAccessTime(online.getLastAccessTime());
    		uo.setExpireTime(online.getExpireTime());
    		uo.setIpaddr(online.getIpaddr());
    		uo.setLoginLocation(online.getLoginLocation());
            uo.setBrowser(online.getBrowser());
            uo.setOs(online.getOs());
            uo.setStatus(online.getStatus());
            uo.setSession(online.getSession());
            
            userOnlineRepository.save(uo);
    	}
    }
    
    /**
     * 通过会话序号查询信息
     * 
     * @param sessionId 会话ID
     * @return 在线用户信息
     */
    @Override
    public UserOnline selectOnlineBySessionId(String sessionId)
    {
    	UserOnline uo = userOnlineRepository.findBySessionId(sessionId);
    	
        return uo;
    }
    
    /**
     * 通过会话序号删除信息
     * 
     * @param sessionId 会话ID
     * @return 在线用户信息
     */
    @Override
    public void deleteOnlineBySessionId(String sessionId)
    {
        UserOnline userOnline = selectOnlineBySessionId(sessionId);
        if (StringUtils.isNotNull(userOnline))
        {
        	userOnlineRepository.deleteById(userOnline.getId());
        }
    }
    
    /**
     * 批量通过会话序号删除信息
     * 
     * @param sessions 会话ID集合
     * @return 在线用户信息
     */
    @Override
    public void batchDeleteOnline(List<String> sessions)
    {
        for (String sessionId : sessions)
        {
            UserOnline userOnline = selectOnlineBySessionId(sessionId);
            if (StringUtils.isNotNull(userOnline))
            {
            	deleteOnlineBySessionId(sessionId);
            }
        }
    }
    
    /**
     * 强退用户
     * 
     * @param sessionId 会话ID
     */
    @Override
    public void forceLogout(String sessionId)
    {
        Session session = onlineSessionDAO.readSession(sessionId);
        if (session == null)
        {
            return;
        }
        session.setTimeout(1000);
        deleteOnlineBySessionId(sessionId);
    }
    
    /**
     * 清理用户缓存
     * 
     * @param loginName 登录名称
     * @param sessionId 会话ID
     */
    @Override
    public void removeUserCache(String loginName, String sessionId)
    {
        Cache<String, Deque<Serializable>> cache = ehCacheManager.getCache(ShiroConstants.SYS_USERCACHE);
        Deque<Serializable> deque = cache.get(loginName);
        if (StringUtils.isEmpty(deque) || deque.size() == 0)
        {
            return;
        }
        deque.remove(sessionId);
    }
    
    /**
     * 根据最后访问时间
     * 查询会话集合
     * 
     * @param online 会话信息
     */
	@Override
	public List<UserOnline> selectOnlineByExpired(Date expiredDate) {
		
		List<UserOnline> uoList = userOnlineRepository.findAll((root, query, cb) ->{
			List<Predicate> list = new ArrayList<>();
			
			if(StringUtils.isNotNull(expiredDate)) {
				list.add(cb.and(cb.lessThanOrEqualTo(root.get("lastAccessTime"), expiredDate)));
			}
			
			Predicate[] p = new Predicate[list.size()];
			return cb.and(list.toArray(p));
		});
		
		return uoList;
	}
}
